package com.xpec.c4.game.system;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Document;

import com.ms.game.common.container.BasicBinUtil;
import com.xpec.c4.game.utility.wordfilter.WordFilters;
import com.xpec.c4.persistence.PersistenceManager;
import com.xpec.c4.persistence.amf3byte.BytesParser;
import com.xpec.c4.persistence.amf3byte.BytesParser.BytesParserHeadInfo;
import com.xpec.c4.service.common.ServiceConfig;

/**
 * 給 TreeMap 排序用的排序器
 * 
 * @author kvn_yang
 * 
 */
class ValueComparator implements Comparator<String> {
	Map<String, BytesParserHeadInfo> baseMap;

	public ValueComparator(Map<String, BytesParserHeadInfo> baseMap) {
		this.baseMap = baseMap;
	}

	@Override
	public int compare(String keyA, String keyB) {
		return keyA.compareTo(keyB);
	}
}

/**
 * 初始化XML数据
 * 
 * @author lipeilin
 * @2010-8-9下午06:14:12
 * 
 */
public class InitData {

	private static final Log log = LogFactory.getLog(InitData.class);

	/**
	 * 项目的根目录
	 */
	public static String projectPath = "";

	/**
	 * 静态数据的根目录
	 */
	public static String editorResourceRootPath = "EditorResource/";

	public static String xmlFolderPath = "xml/";

	public static String byteFolderPath = "byte/";

	public static HashMap<String, Object> alreadyLoaded = new HashMap<String, Object>();

	public static HashMap<String, BytesParserHeadInfo> dataHeaders = new HashMap<String, BytesParserHeadInfo>();

	/**
	 * 是否已经加载过全部
	 */
	private static boolean isInitAllAlready = false;

	static {
		projectPath = ServiceConfig.rootPath;
		editorResourceRootPath = projectPath + "/" + editorResourceRootPath;
		log.info(editorResourceRootPath);

		// PersistenceManager pm = PersistenceManager.getInstance();
		// pm.init(editorResourceRootPath + xmlFolderPath);
		log.info("init data");
	}

	/**
	 * 加载数据文件
	 * 
	 * @param path
	 * @return
	 * 
	 * @author lipeilin
	 * @2011-5-28 下午02:36:28
	 */
	public static Object loadData(String path) {
		// if (path.endsWith("xml")) {
		// return loadXML(path);
		// }
		if (path.endsWith("bin")) {
			return loadByte(path);
		}
		return null;

	}

	/**
	 * 加载XML数据
	 * 
	 * @param xmlPath
	 * @return
	 * 
	 * @author lipeilin
	 * @2011-2-22 下午06:14:35
	 */
	@SuppressWarnings("unused")
	public static Object loadXML(String xmlPath) {

		// 先从Contexts找，没有再加载文件
		// Object obj = Contexts.getGroupContext().get(xmlPath);
		Object obj = null;

		// 如果已经加载，则不再加载
		if (alreadyLoaded.containsKey(xmlPath)) {
			if (log.isDebugEnabled()) {
				log.debug("load file already exist:" + xmlPath);
			}
			return alreadyLoaded.get(xmlPath);
		}

		// 如果对象是空，则从文件加载
		if (obj == null) {
			try {
				String filepath = editorResourceRootPath + xmlFolderPath + xmlPath;
				log.info("load file data resource:" + filepath);
				Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder()
						.parse(new java.io.File(filepath));
				obj = PersistenceManager.getInstance().parse(doc.getDocumentElement());
			} catch (Exception e) {
				log.error("load file data resource error!" + xmlPath, e);
			}
			// Contexts.getGroupContext().set(xmlPath, obj);
		}
		// 如果有，看是否需要赋值到单例
		else {
			log.info("load group data resource:" + xmlPath);
			obj = setSingletonContianer(obj);
		}

		// 标记已经加载
		alreadyLoaded.put(xmlPath, obj);

		return obj;
	}

	/**
	 * 
	 * @param filePath
	 * @return
	 */
	public static Object loadByteWithoutHeader(String filePath) {

		Object obj = null;

		// 如果已经加载，则不再加载
		if (alreadyLoaded.containsKey(filePath)) {
			if (log.isDebugEnabled()) {
				log.debug("load file already exist:" + filePath);
			}
			return alreadyLoaded.get(filePath);
		}

		// 如果对象是空，则从文件加载
		try {
			String filepath = editorResourceRootPath + byteFolderPath + filePath;
			if (log.isInfoEnabled()) {
				log.info("load file data resource:" + filepath);
			}
			BytesParser bp = new BytesParser();
			obj = bp.parse(filepath);

			// Contexts.getGroupContext().set(filePath, obj);
		} catch (Exception e) {
			if (log.isErrorEnabled()) {
				log.error("load file data resource error!" + filePath, e);
			}
		}

		obj = setSingletonContianer(obj);
		// 标记已经加载
		alreadyLoaded.put(filePath, obj);
		return obj;
	}

	/**
	 * 加载byte数据
	 * 
	 * @param filePath
	 * @return
	 * 
	 * @author lipeilin
	 * @2011-2-22 下午06:14:43
	 */
	@SuppressWarnings("unused")
	public static Object loadByte(String filePath) {

		// 先从Contexts找，没有再加载文件
		// Object obj = Contexts.getGroupContext().get(filePath);
		Object obj = null;

		// 如果已经加载，则不再加载
		if (alreadyLoaded.containsKey(filePath)) {
			if (log.isDebugEnabled()) {
				log.debug("load file already exist:" + filePath);
			}
			return alreadyLoaded.get(filePath);
		}

		// 如果对象是空，则从文件加载
		if (obj == null) {
			try {
				String filepath = editorResourceRootPath + byteFolderPath + filePath;
				if (log.isInfoEnabled()) {
					log.info("load file data resource:" + filepath);
				}
				BytesParser bp = new BytesParser();
				BytesParserHeadInfo header = bp.new BytesParserHeadInfo();
				obj = bp.parseWithHeader(filepath, header);

				if (obj != null) {
					dataHeaders.put(filePath, header);
				}
				// Contexts.getGroupContext().set(filePath, obj);
			} catch (Exception e) {
				if (log.isErrorEnabled()) {
					log.error("load file data resource error!" + filePath, e);
				}
			}
		} else {
			if (log.isInfoEnabled()) {
				log.info("load group data resource:" + filePath);
			}
		}

		obj = setSingletonContianer(obj);

		// 載入後的處理
		callBinPreProcMethod(obj);

		// 标记已经加载
		alreadyLoaded.put(filePath, obj);
		return obj;
	}

	/**
	 * 呼叫數據檔被載入後的預處理事件
	 * 
	 * @param obj
	 *            bin instance
	 */
	private static void callBinPreProcMethod(Object obj) {
		Exception exception = null;

		try {
			String className = obj.getClass().getName() + "Util";
			Class<?> c = Class.forName(className);
			if (BasicBinUtil.class.isAssignableFrom(c)) {
				Method m = c.getMethod("onBinLoad", Object.class);
				Object binUtilObj = Class.forName(className).newInstance();
				m.invoke(binUtilObj, obj);
			}
		} catch (InstantiationException e) {
			exception = e;
		} catch (IllegalAccessException e) {
			exception = e;
		} catch (ClassNotFoundException e) {
		} catch (IllegalArgumentException e) {
			exception = e;
		} catch (InvocationTargetException e) {
			exception = e;
		} catch (NoSuchMethodException e) {
			exception = e;
		} catch (SecurityException e) {
			exception = e;
		}

		if (exception != null) {
			if (log.isErrorEnabled()) {
				log.error("call onBinLoad proc fail.", exception);
			}
		}
	}

	/**
	 * 加载服务器组数据对象，如果是单例，则赋值至单例内
	 * 
	 * @param obj
	 * @return
	 * 
	 * @author lipeilin
	 * @2011-2-22 下午06:15:18
	 */
	private static Object setSingletonContianer(Object obj) {
		try {
			Method method = obj.getClass().getDeclaredMethod("setInstance", obj.getClass());
			// 单例设值
			if (method != null) {
				method.invoke(obj, obj);
				// 永久解決兩岸關係.....20150708
				/*
				 * Field field = null;
				 * try {
				 * field = obj.getClass().getDeclaredField("instance");
				 * } catch (Exception e) {
				 * field = obj.getClass().getDeclaredField("container");
				 * }
				 * field.setAccessible(true);
				 * //getInstance()是static method,因此instance或container也必定是static
				 * field.
				 * //set static field value不需要target
				 * object.直接call放parameter進去即可lip
				 * if (field != null) {
				 * field.set(null, obj);
				 * }
				 */
			}
		} catch (Exception e) {
			if (log.isErrorEnabled()) {
				log.error(obj + " is not Singleton Contianer!", e);
			}
		}
		return obj;
	}

	/**
	 * 设定
	 * 
	 * @param projectPath
	 */
	public static void setProjectPath(String projectPath) {
		System.out.println("setProjectPath");
		InitData.projectPath = projectPath;
		PersistenceManager pm = PersistenceManager.getInstance();
		pm.init(projectPath + "EditorResource/xml/");
	}

	/**
	 * 加载屏蔽字库
	 */
	private static void initWordFilter() {
		WordFilters.setRootPath("./config/");
		WordFilters.reloadAccountWordFilter();
		WordFilters.reloadChatWordFilter();
	}

	/**
	 * 初始化全部的XML数据
	 */
	public static void initAll() {

		if (isInitAllAlready) {
			if (log.isInfoEnabled()) {
				log.info("init all data is alreay load!");
			}
			return;
		}

		isInitAllAlready = true;

		// =================================================================
		// 過濾字載入

		initWordFilter();

		// =================================================================
		// 數據載入

		// client only
		loadByte("StringTableBin.bin");

		// robot used..
		loadByte("AnyNameBin.bin");
		loadByte("RobotNickName.bin");

		// 銀行
		loadByte("BankInfoBin.bin");

		// 基本設定
		loadByte("BasicSetting.bin");
		loadByte("BasicSettingServerBin.bin");

		loadByte("GameLimitInfo.bin");
		loadByte("GameOptionSetting.bin");

		// 邀請碼獎勵
		loadByte("InviteCodeRewardBin.bin");

		// 道具
		loadByte("ItemBoxBin.bin");

		// 等級
		loadByte("LevelInfoBin.bin");

		// 連續登入獎勵
		loadByte("ContinuousLoginRewardBin.bin");

		// 付費
		loadByte("PurchaseData.bin");

		// 遊戲警示系統
		loadByte("GameOperateAlertInfo.bin");
		
		// 百家樂
		loadByte("BacrBasic.bin");
		loadByte("BacrAdvance.bin");
		loadByte("BacrMachineSetting.bin");
		
		// 捕鱼配置
		loadByte("FishSetting.bin");

		// =================================================================
		// 建立數據檔頭資訊清單（為了能輸出所有已載入的數據檔頭，請保持在最後面）

		createDataHeaderListFile();
	}

	/**
	 * 建立數據檔頭資訊清單
	 */
	public static void createDataHeaderListFile() {
		// 產生檔案內容
		String quote = "\"";
		String newLine = "\n";

		// 用來排序的 map
		ValueComparator bvc = new ValueComparator(dataHeaders);
		TreeMap<String, BytesParserHeadInfo> sorted_map = new TreeMap<String, BytesParserHeadInfo>(bvc);
		sorted_map.putAll(dataHeaders);

		// 欄位名稱
		String fileContent = quote + "File Name" + quote + "," + quote + "computer Name" + quote + "," + quote
				+ "Create Time" + quote + newLine;
		for (Map.Entry<String, BytesParserHeadInfo> entry : sorted_map.entrySet()) {
			// bin 檔名稱
			String dataFileName = entry.getKey();

			// 檔頭資訊
			BytesParserHeadInfo header = entry.getValue();

			// 要寫入的結果字串
			String insertString = quote + dataFileName + quote + "," + quote + header.getHostName() + quote + ","
					+ quote + header.getCreateTime() + quote + newLine;

			fileContent += insertString;
		}

		// 建立檔案
		String fileName = "StaticDataInfo.csv";

		BufferedWriter writer = null;
		try {
			File file = new File(fileName);
			writer = new BufferedWriter(new FileWriter(file));
			writer.write(fileContent);
		} catch (Exception e) {
			if (log.isErrorEnabled()) {
				log.error("Write file " + fileName + " fail.", e);
			}
			return;
		} finally {
			try {
				// 關閉檔案
				writer.close();
			} catch (Exception e) {
				if (log.isErrorEnabled()) {
					log.error("Close file " + fileName + " fail.", e);
				}
			}
		}
	}
}
